#ifndef ACTIONTIMELINE_H
#define ACTIONTIMELINE_H

#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QGraphicsLineItem>
#include <QSlider>
#include <QTimer>
#include <QDoubleSpinBox>

#include "robotaction.h"
#include "keyframedialog.h"
#include "editabletimelineitem.h"

class GUIActionTimeline;

/*********************************************************/
/*              GUI MOTION KEY FRAME CLASS               */
/*********************************************************/
class GUIMotionKeyFrame : public GUIEditableTimelineItem{

public:
    GUIMotionKeyFrame(int timestamp, QPixmap* pixmap, QPixmap* hoverPixmap,
                      GUIActionTimeline* timeline, QGraphicsItem* parent = 0);

protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
    void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
    QRectF boundingRect() const;

private:
    QPixmap *_pixmap, *_hoverPixmap;
    bool _hover;
};


/*********************************************************/
/*                GUI MOTION TRACK CLASS                 */
/*********************************************************/
class GUIMotionTrack : public GUITimelineTrack{
    Q_OBJECT

public:
    GUIMotionTrack(RobotMotionTrack* motionTrack, GUIActionTimeline* timeline, QGraphicsItem* parent = 0);

protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    GUIEditableTimelineItem* createItem(int timestamp);
    void onItemMovedInGUI(int newTimestamp, int oldTimestamp);
    void onDeleteConfirmed(GUIEditableTimelineItem *item);

private:
    QPixmap *_keyFramePixmap, *_keyFrameHoverPixmap;
    void createItems();

private slots:
    void onMotionDurationChanged(int newMsec, int oldMsec);
};


/*********************************************************/
/*                    GUI SOUND CLASS                    */
/*********************************************************/
//Unfortunately, we cannot inherit from both EditableTimelineItem and QGraphicsRectItem
//because of the "diamond inheritance" problem (i.e., both classes inherit from QGraphicsItem
//and it is ambiguous).  The normal solution is to declare both as virtually inheriting from
//QGraphicsItem, but QGraphicsRectItem does not, and I don't want to change the Qt source.  The
//best solution is to have the EditableTimelineItem implement QAbstractGraphicsShapeItem,
//and implement the QGraphicsItem::boundingRect() function.  This is okay because
//I was going to be doing custom painting of the sound box anyway, which means that the only
//convenience of QGraphicsRectItem was that it had boundingRect() defined.
class GUISound : public GUIEditableTimelineItem{
public:
    GUISound(int timestamp, QString filename, int duration,
                GUIActionTimeline* timeline, QGraphicsItem* parent = 0);

    void setDuration(int msec);
    int duration() const;

    SoundInfo getSoundInfo() const;

protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    QRectF boundingRect() const;

    //The things are in place to start implementing a drag-to-clip sound ability,
    //but there needs to be a change in the file format to save it
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);

    void hoverMoveEvent(QGraphicsSceneHoverEvent *event);

private:
    enum TrimDirection{
        NONE,
        LEFT,
        RIGHT
    };

    int _duration, _durationBeforeTrim;
    QString _filename;
    TrimDirection _trimDirection;
    bool _trimming;
    ActionCommandGroup* _trimGroupCommand;
};


/*********************************************************/
/*                 GUI SOUND TRACK CLASS                 */
/*********************************************************/
class GUISoundTrack: public GUITimelineTrack{
    Q_OBJECT
public:
    GUISoundTrack(SoundTrack* soundTrack, GUIActionTimeline* timeline, QGraphicsItem* parent=0);

    friend SoundInfo GUISound::getSoundInfo() const;

protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

    GUIEditableTimelineItem* createItem(int timestamp);
    void onItemMovedInGUI(int newTimestamp, int oldTimestamp);
    void onDeleteConfirmed(GUIEditableTimelineItem *item);

private:
    void createItems();
    GUIEditableTimelineItem* createGUISound(int timestamp, int duration, QString filename);

protected slots:
    void onSoundDurationChanged(int msec, int newDuration);
};


/*********************************************************/
/*               GUI POSITION LINE CLASS                 */
/*********************************************************/
class GUIPositionLine : public QObject, public QGraphicsLineItem{
    Q_OBJECT

public:
    GUIPositionLine(GUIActionTimeline* timeline);

    int positionToMsec();
    void setPosition(int msec);

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
    QVariant itemChange(GraphicsItemChange change, const QVariant &value);

private:
    GUIActionTimeline* _timeline;

signals:
    void pastBoundary(int amount);
};


/*********************************************************/
/*               GUI TIMELINE RULER CLASS                */
/*********************************************************/
class GUITimelineRuler : public QObject, public QGraphicsRectItem{
    Q_OBJECT

public:
    GUITimelineRuler(GUIActionTimeline* timeline);

    void setTickInterval(int msec);
    void setMajorTickInterval(int msec);
    void setTickHeight(int px);
    void setMajorTickHeight(int px);

protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);

private:
    GUIActionTimeline* _timeline;

    int _tickInterval;
    int _majorTickInterval;
    int _tickHeight;
    int _majorTickHeight;

    void drawTicks(QPainter *painter);

signals:
    void rulerClicked(int msec);
    void mouseMove(int msec);
    void mouseRelease();
};


/*********************************************************/
/*              GUI ACTION TIMELINE CLASS                */
/*********************************************************/
class GUIActionTimeline : public QGraphicsView
{
    Q_OBJECT
public:
    explicit GUIActionTimeline(QWidget *parent = 0);

    enum ScrollOption{
        OFF,
        LEFT,
        RIGHT
    };

    void loadAction(RobotAction* action);
    float curScale() const{return _curScale;}
    int offset() const{return _timelineOffset;}
    int upperBound() const{return _upperBound;}
    int lowerBound() const{return _lowerBound;}
    int currentTime() const{return _curTime;}

    RobotAction* action(){return _curAction;}

protected:
    void resizeEvent(QResizeEvent *event);
    void changeEvent(QEvent *event);

private:
    float _curScale;
    float _scaleMin;
    float _scaleMax;

    int _upperBound;
    int _lowerBound;

    int _curTime;
    int _timelineOffset;
    ScrollOption _scrollOption;

    RobotAction* _curAction;
    QGraphicsScene* _scene;
    GUITimelineRuler *_ruler;
    GUIMotionTrack* _motionTrack;
    GUISoundTrack* _soundTrack;
    QGraphicsRectItem *_bottomRect, *_disabledOverlay;
    QSlider* _scaleSlider;
    QDoubleSpinBox* _timeSpinBox;
    GUIPositionLine *_positionLine;

    QList<QGraphicsLineItem*> _stretchableLines;

    QTimer* _scrollTimer;

    QBrush _grayBrush;

    void initScene();
    void initInfoArea();
    float calculateScale(int val);

signals:
    void editingKeyFrame(int msec);
    void editingSound(int msec);
    void editingFinished();
    void needAction();

public slots:
    void setScale(float scale);
    void setTime(int msec);
    void scroll(ScrollOption option);
    void stopScroll();

private slots:
    void onSliderChanged(int newVal);
    void onSpinBoxChanged(double val);
    void onRulerClicked(int msec);
    void onRulerMouseMove(int msec);
    void onRulerMouseRelease();
    void onPastBoundary(int amount);
    void onScrollTimeout();
    void onKeyFrameBtnClicked();
    void onSoundBtnClicked();
    void onEdit(int timestamp);
    void onEditFinished(int timestamp);
};

#endif // ACTIONTIMELINE_H
